package service

import (
	"fmt"
	"gitee.com/bigmouth/quick-mock/src/domain/entity"
	"gitee.com/bigmouth/quick-mock/src/infrastructure/log"
	uuid "github.com/satori/go.uuid"
	"html/template"
	"sync"

	"gitee.com/bigmouth/quick-mock/src/domain/agg"
)

var namespaceInstance *NamespaceContainer
var once sync.Once
var lock = &sync.RWMutex{}

// NamespaceContainer 命名空间容器
type NamespaceContainer struct {
	container map[string]*agg.Namespace
}

func GetNamespaceInstance() *NamespaceContainer {
	once.Do(func() {
		namespaceInstance = &NamespaceContainer{
			container: make(map[string]*agg.Namespace),
		}
	})
	return namespaceInstance
}

// Create 添加命名空间
func (n *NamespaceContainer) Create(lifeTime int64) string {
	lock.Lock()
	defer lock.Unlock()
	namespace := uuid.NewV4().String()
	n.container[namespace] = agg.NewNamespace(namespace, lifeTime)
	return namespace
}

// AddMockApi 添加mock接口
func (n *NamespaceContainer) AddMockApi(namespace, responseDataStr string, delay int64, matchRules []entity.MatchRule) error {
	lock.Lock()
	defer lock.Unlock()
	if namespaceAgg, ok := n.container[namespace]; ok {
		if namespaceAgg.IsLive() {
			var tpl *template.Template
			if responseDataStr != "" {
				responseTpl, err := template.New("mockResponse").Parse(responseDataStr)
				if err != nil {
					return fmt.Errorf("responseJsonData解析错误，请检查是否符合go template语法, err=%s", err)
				}
				tpl = responseTpl
			}

			n.container[namespace].AddMockApi(entity.NewMockApi(matchRules, responseDataStr, tpl, delay))
			return nil
		} else {
			// 删除超时时间
			delete(n.container, namespace)
		}

	}
	return fmt.Errorf("namespace: %s不存在, 请先调用create接口", namespace)

}

// MatchMock 匹配mock
func (n *NamespaceContainer) MatchMock(namespace string, path, method string, header, queryParam map[string]string, bodyJson map[string]interface{}) (entity.MockApi, bool, error) {
	lock.RLock()
	namespaceAgg, ok := n.container[namespace]
	lock.RUnlock()
	if ok {
		if namespaceAgg.IsLive() {
			return namespaceAgg.FindMockApi(path, method, header, queryParam, bodyJson)
		} else {
			lock.Lock()
			// 删除超时命名空间
			delete(n.container, namespace)
			lock.Unlock()
		}
	}
	return entity.MockApi{}, false, fmt.Errorf("namespace: %s不存在, 请先调用create接口", namespace)
}

// GetNamespaceAndDisableTimeMap 获取命名空间和失效时间map
func (n *NamespaceContainer) GetNamespaceAndDisableTimeMap() map[string]string {
	lock.RLock()
	defer lock.RUnlock()
	result := make(map[string]string, len(n.container))
	for namespace, aggPtr := range n.container {
		result[namespace] = aggPtr.GetDisableTimeStr()
	}
	return result
}

func (n *NamespaceContainer) GetMocksByNamespace(namespace string) (agg.Namespace, bool) {
	if namespaceAgg, ok := n.container[namespace]; ok {
		if namespaceAgg.IsLive() {
			return *namespaceAgg, true
		} else {
			// 删除超时命名空间
			lock.Lock()
			delete(n.container, namespace)
			lock.Unlock()
		}
	}
	return agg.Namespace{}, false
}

func (n *NamespaceContainer) CleanTimeout() {
	lock.Lock()
	defer lock.Unlock()
	log.Info("clean start")
	count := 0
	for namespace, namespaceAgg := range n.container {
		if !namespaceAgg.IsLive() {
			count += 1
			delete(n.container, namespace)
		}
	}
	log.Info("clean end, total clean %d", count)
}
